package golang

import "gitee.com/allowall-package/goutil/fn"

// 观察者接口，每个观察者需要实现一个变化时具体的操作
type Observer interface {
	Update(*Subject)
}

// 被观察者
type Subject struct {
	observers []Observer
	sign      string
}

// 初始化被观察者
func NewSubject() *Subject {
	return &Subject{
		observers: make([]Observer, 0),
	}
}

// 给被观察者添加依赖的观察者
func (s *Subject) Attach(o Observer) {
	s.observers = append(s.observers, o)
}

// 给被观察者执行某个动作
func (s *Subject) UpdateSign(sign string) {
	s.sign = sign
	s.notify()
}

// 广播通知与被观察者依赖的观察者
func (s *Subject) notify() {
	for _, o := range s.observers {
		o.Update(s)
	}
}

// ---------------分割线---------------

// 某一个观察者类
type Reader struct {
	name string
}

// 新建观察者
func NewReader(name string) *Reader {
	return &Reader{name: name}
}

// 观察者被通知变化时具体的操作
func (r *Reader) Update(s *Subject) {
	fn.Dumpf("%s receive %s", r.name, s.sign)
}

// ---------------分割线---------------

// 测试方法
func ObserverTest() {
	fn.Dump(fn.FuncInfo())

	subject := NewSubject()
	subject.Attach(NewReader("reader1"))
	subject.Attach(NewReader("reader2"))
	subject.Attach(NewReader("reader3"))

	subject.UpdateSign("golang")
	subject.UpdateSign("php")
}
